
#include <libpar2/par2cmdline.h>
#include <libpar2/par2repairer.h>
#include "string.h"
#include "kparengine.h"

KparEngine::KparEngine(Kpar* kpar_gui)
{
    this->kpar_gui = kpar_gui;
    operation = noop;
    total_files = 0;
    processed_files = 0;
    files_damaged = 0;
    files_missing = 0;
    par2repairer = NULL;
    cmdline = NULL;
    to_be_repaired = false;

}

KparEngine::~KparEngine()
{
    delete par2repairer;
    delete cmdline;
    QApplication::sendPostedEvents();
}

bool KparEngine::loadPAR2Files( const QString& par2file )
{
    bool result = false;
    if( !par2file.isEmpty() ){

        operation = load;
        QApplication::postEvent( kpar_gui, new UpdateStatusBar("Loading parity files..."));
        total_files = 0;
        processed_files = 0;

        if( cmdline == NULL ){
            cmdline = new CommandLine();
        }else{
            delete cmdline;
            cmdline = new CommandLine();
        }

        if( par2repairer == NULL ){
            par2repairer = new Par2Repairer();
        }else{
            delete par2repairer;
            par2repairer = new Par2Repairer();
        }

        par2repairer->sig_filename.connect( sigc::mem_fun( *this, &KparEngine::signal_filename ));
        par2repairer->sig_progress.connect( sigc::mem_fun( *this, &KparEngine::signal_progress ) );
        par2repairer->sig_headers.connect( sigc::mem_fun( *this, &KparEngine::signal_headers ) );
        par2repairer->sig_done.connect( sigc::mem_fun( *this, &KparEngine::signal_done ) );

        const char *program = "par2verify";
        QByteArray temp = par2file.toLocal8Bit();
        const char *char_par2file = temp.constData();
        char *argv[] = { const_cast<char*>( program ), const_cast<char*>( char_par2file ) };

        cmdline->Parse( 2, argv );

        if( par2repairer->PreProcess( *cmdline ) == eSuccess ){
            result = true;
        }else{

            result = false;
        }

        QApplication::postEvent( kpar_gui, new UpdateProgress(0, file));
        QApplication::postEvent( kpar_gui, new UpdateStatusBar("Parity files loaded."));
        operation = noop;
    }
    return result;
}

bool KparEngine::checkParity( const QString& par2file )
{
    bool result = false;

    if( !par2file.isEmpty() ){
        operation = verify;
        QApplication::postEvent( kpar_gui, new UpdateProgress(0, file));
        QApplication::postEvent( kpar_gui, new UpdateProgress(0, total));
        QApplication::postEvent( kpar_gui, new UpdateStatusBar("Verifying source files..."));

        const char *program = "par2verify";
        QByteArray temp = par2file.toLocal8Bit();
        const char *char_par2file = temp.constData();

        char *argv[] = {const_cast<char*>( program ), const_cast<char*>( char_par2file  )};
        if (cmdline !=NULL)
        {
            cmdline->Parse( 2, argv );
            if( par2repairer->Process( *cmdline, false ) == eRepairPossible ){
               result = true;
               QApplication::postEvent( kpar_gui, new UpdateListe(QString("%1 %2 damaged, %3 %4 missing." ).arg( files_damaged ).arg( ( files_damaged == 1 ) ? i18n( "file is" ) : i18n( "files are" ) ).arg( files_missing ).arg( ( files_missing == 1 ) ? i18n( "file is" ) : i18n( "files are" ) ), warning));
               QApplication::postEvent( kpar_gui, new UpdateStatusBar("Repair is required." ));
            }else{

                if( files_missing + files_damaged == 0 ){
                    QApplication::postEvent( kpar_gui, new UpdateListe(QString("All files are correct, repair is not required." ), ok));
                    QApplication::postEvent( kpar_gui, new UpdateStatusBar("All files are correct"));
                }else{
                    QApplication::postEvent( kpar_gui, new UpdateListe(QString( "%1 %2 damaged, %3 %4 missing." ).arg( files_damaged ).arg( ( files_damaged == 1 ) ? i18n( "file is" ) : i18n( "files are" ) ).arg( files_missing ).arg( ( files_missing == 1 ) ? i18n( "file is" ) : i18n( "files are" ) ), error));
                    QApplication::postEvent( kpar_gui, new UpdateStatusBar("Repair is not possible." ));
                }
            }
            processed_files = 0;
            operation = noop;
        }
    }
    return result;
}

bool KparEngine::repairFiles( const QString& par2file )
{
    bool result = false;

    if( !par2file.isEmpty() ){
        operation = repair;

        QApplication::postEvent( kpar_gui, new UpdateStatusBar("Repairing files..." ) );

        const char *program = "par2repair";
        QByteArray temp = par2file.toLocal8Bit();
        const char *char_par2file = temp.constData();

        char *argv[] = {const_cast<char*>( program ), const_cast<char*>( char_par2file )};
         if (cmdline !=NULL)
        {
            cmdline->Parse( 2, argv );

            if( par2repairer->Process( *cmdline, true ) == eSuccess ){
                result = true;
                files_damaged = 0;
                files_missing = 0;
                QApplication::postEvent( kpar_gui, new UpdateStatusBar("Repair complete." ));
            }else{
                QApplication::postEvent( kpar_gui, new UpdateStatusBar("Repair failed." ));
            }
        }

        operation = noop;
    }

    return result;
}

void KparEngine::signal_filename( std::string str )
{
        if( this->operation == load ){
             QApplication::postEvent( kpar_gui, new UpdateListe(QString(str.c_str()), info));
        }
}

void KparEngine::signal_progress( double value )
{
    double current_progress = value/10.0;
    QApplication::postEvent( kpar_gui, new UpdateProgress(current_progress, file));
}

void KparEngine::signal_headers( ParHeaders* headers )
{
    total_files = headers->recoverable_files;
    HeaderInfo *he = new HeaderInfo( headers );
    QString text = i18n( qPrintable("There are " + QString::number( he->headers()->recoverable_files ) + \
                   " recoverable files and " +  QString::number( he->headers()->other_files ) + \
                   " other files.\n" + "The block size used was " + \
                   QString::number( he->headers()->block_size ) + "\nThere are a total of " + \
                   QString::number( he->headers()->data_blocks ) + " data blocks.\n" + \
                   "The total size of the data files is " + \
                   QString::number( abs( he->headers()->data_size ) ) + " bytes." ));
    QApplication::postEvent( kpar_gui, new UpdateListe(text, info));
}

void KparEngine::signal_done( std::string filename, int blocks_available, int blocks_total )
{
    processed_files++;
    int data = blocks_total - blocks_available;

    if( operation == verify ){

        if( total_files > 0 ){
            int progress = static_cast<int>( ( static_cast<double>( processed_files )/ static_cast<double>( total_files ) ) * 100.00 );
            QApplication::postEvent( kpar_gui, new UpdateProgress(progress, total));
        }

    }else if( operation == repair ){

        if( total_files > 0 ){
            int progress = static_cast<int>( ( static_cast<double>( processed_files )/ static_cast<double>( files_damaged + files_missing ) ) * 100.00 );
            QApplication::postEvent( kpar_gui, new UpdateProgress(progress, total));
        }
    }
    if( data == 0 ){
          QApplication::postEvent( kpar_gui, new UpdateListe(QString(filename.c_str()), ok));
    }else if( data < blocks_total ){
        files_damaged++;
         QApplication::postEvent( kpar_gui, new UpdateListe(QString(filename.c_str()), warning));
    }else if( data == blocks_total ){
        files_missing++;
         QApplication::postEvent( kpar_gui, new UpdateListe(QString(filename.c_str()), error));
    }
}
